using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Collections;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using System.Text.RegularExpressions;
using Adoor.Metadata;

namespace Adoor.Wizard
{
    public partial class Wizard : Form
    {
        public Wizard()
        {
            InitializeComponent();
            dsProject = new DataSet();
        }

        private DataSet dsProject;
        private const string ProjectDataSet = "Dataset";
        private const string ProjectInput = "input";
        private const string ProjectDest = "output";
        private const string ProjectPivotFile = "ProjectPivotFile";
        private const string ProjectMappingFile = "ProjectMappinFile";
        private const string ProjectCodeFile = "ProjectCodeFile";
        private const string ProjectDbFile = "ProjectDbFile";
        private const string ProjectGenerateMapping = "GenerateMapping";
        private const string ProjectGenerateCode = "GenerateCode";
        private const string ProjectGenerateDb = "GenerateDB";

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            fillCombo(comboBoxXmi, "Xmi*.xslt");
            fillCombo(comboBoxCode, "Code*.xslt");
            fillCombo(comboBoxDb, "Db*.xslt");
            fillCombo(comboBoxMapping, "Map*.xslt");
        }

        private void fillCombo(ComboBox combo, string pattern)
        {
            foreach (string s in Directory.GetFiles(Application.StartupPath, pattern))
            {
                combo.Items.Add(Path.GetFileName(s));
            }
            combo.SelectedIndex = 0;
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openProject();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void buttonSelectInputXMI_Click(object sender, EventArgs e)
        {
            openXmi();
        }

        private void buttonChooseOutput_Click(object sender, EventArgs e)
        {
            using (FolderBrowserDialog fbd = new FolderBrowserDialog())
            {
                if (fbd.ShowDialog() == DialogResult.OK)
                {
                    textBoxOutput.Text = fbd.SelectedPath;
                }
            }
        }

        public DataTable TableUMLDataTypes
        {
            get { return ensureUMLDataTypes(); }
        }

        private DataTable ensureUMLDataTypes()
        {
            string tableName = "XmiTypeConvertion";
            string confSection = "defaultUMLDataType";
            return ensureTableDefault(tableName, confSection);
        }

        public DataTable TableClassIds
        {
            get { return dsProject.Tables["UUID"]; }
        }

        public DataTable TableCodeDefault
        {
            get { return ensureCodeDefault(); }
        }

        private DataTable ensureCodeDefault()
        {
            string tableName = "Code";
            string confSection = "defaultCodeValues";
            return ensureTableDefault(tableName, confSection);
        }

        public DataTable TableDbDefault
        {
            get { return ensureDbDefault(); }
        }

        private DataTable ensureDbDefault()
        {
            string tableName = "DB";
            string confSection = "defaultDBValues";
            return ensureTableDefault(tableName, confSection);
        }

        private DataTable ensureTableDefault(string tableName, string confSection)
        {
            DataTable dt = dsProject.Tables[tableName];

            if (dt == null)
            {
                dt = new DataTable(tableName);
                dt.Columns.Add("type", typeof(string));
                dt.Columns.Add("value", typeof(string));

                Hashtable nvc = System.Configuration.ConfigurationManager.GetSection(confSection) as Hashtable;

                string defaultVal = "0";
                if (nvc == null)
                {
                    dt.Rows.Add(" default", defaultVal);
                }
                else
                {
                    foreach (System.Collections.DictionaryEntry entry in nvc)
                    {
                        if (string.Compare(entry.Key.ToString(), "default", true) == 0)
                            dt.Rows.Add(" default", entry.Value.ToString());
                        else
                        {
                            dt.Rows.Add(new object[] { entry.Key, entry.Value });
                        }
                    }
                }
                dsProject.Tables.Add(dt);
            }

            return dt;
        }


        private void buttonTypes_Click(object sender, EventArgs e)
        {
            using (FormTypeConvertion ftc = new FormTypeConvertion())
            {
                ftc.DataTable = this.TableUMLDataTypes;
                ftc.XmiFilePath = textBoxXmiFilePath.Text;
                ftc.ShowDialog();
            }
        }

        private void buttonDefaultCode_Click(object sender, EventArgs e)
        {
            using (FormTable ftc = new FormTable())
            {
                ftc.DataTable = this.TableCodeDefault;
                ftc.ShowDialog();

            }
        }

        private void buttonDefaultDB_Click(object sender, EventArgs e)
        {
            using (FormTypeConvertion ftc = new FormTypeConvertion())
            {
                ftc.DataTable = this.TableDbDefault;
                ftc.ShowDialog();

            }
        }

        bool generateCode;
        bool generateMapping;
        bool generateDb;
        string xsltCode;
        string xsltMapping;
        string xsltDb;

        private void buttonStart_Click(object sender, EventArgs e)
        {
            generateCode = checkBoxCode.Checked;
            generateMapping = checkBoxMapping.Checked;
            generateDb = checkBoxDBScripts.Checked;
            xsltCode = Path.Combine(Application.StartupPath, comboBoxCode.Text);
            xsltMapping = Path.Combine(Application.StartupPath, comboBoxMapping.Text);
            xsltDb = Path.Combine(Application.StartupPath, comboBoxDb.Text);

            startTransforms();

        }

        private void startTransforms()
        {
            wait = true;

            WaitCallback wc = new WaitCallback(transforms);
            wc.BeginInvoke(null,
                new AsyncCallback(endTransforms),
                wc);
        }

        private void endTransforms(IAsyncResult result)
        {
            try
            {
                WaitCallback wc = (WaitCallback)result.AsyncState;
                wc.EndInvoke(result);


            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            finally
            {
                wait = false;
            }
        }

        private void openXmi()
        {
            using (OpenFileDialog of = new OpenFileDialog())
            {
                of.Title = "Select xmi file";
                of.Filter = "Xmi files (*.xmi; *.xml)|*.xmi;*.xml|All files (*.*)|*.*";
                of.FilterIndex = 0;
                if (of.ShowDialog() == DialogResult.OK)
                {
                    textBoxXmiFilePath.Text = of.FileName;
                }
            }
        }

        private int waitCnt;
        private bool wait
        {
            get
            {
                return waitCnt != 0;
            }
            set
            {
                bool oldState = wait;
                if (value)
                    waitCnt++;
                else
                    waitCnt--;
                if (oldState != wait)
                    onWaitChanged();
            }
        }

        private void onWaitChanged()
        {
            Invoke(new ThreadStart(delegate()
            {
                bool newWait = wait;
                foreach (Control ctrl in Controls)
                {
                    ctrl.Enabled = !wait;
                }
                UseWaitCursor = wait;
            }));
        }

        private void buttonAnalyse_Click(object sender, EventArgs e)
        {
            startXmiTransform();
        }

        string outputPath;
        string xmiXslt;
        private void startXmiTransform()
        {
            wait = true;

            outputPath = textBoxOutput.Text;
            xmiXslt = Path.Combine(Application.StartupPath, comboBoxXmi.Text);

            WaitCallback wc = new WaitCallback(xmiTransform);
            wc.BeginInvoke(textBoxXmiFilePath.Text,
                new AsyncCallback(endXmiTransform),
                wc);
        }

        private void endXmiTransform(IAsyncResult result)
        {
            try
            {
                WaitCallback wc = (WaitCallback)result.AsyncState;
                wc.EndInvoke(result);

                Invoke(new ThreadStart(AnalyseResultOK));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                Invoke(new ThreadStart(AnalyseResultKO));
            }
            finally
            {
                wait = false;
            }
        }

        private void AnalyseResultOK()
        {
            groupBoxGeneration.Enabled = true;
            buttonUUIDs.Enabled = true;
        }

        private void AnalyseResultKO()
        {
            groupBoxGeneration.Enabled = false;
            buttonUUIDs.Enabled = false;
        }

        private void xmiTransform(object path)
        {
            if (!System.IO.Directory.Exists(outputPath))
            {
                System.IO.Directory.CreateDirectory(outputPath);
            }

            string outXslt = generateXsltXmiFile((string)path);
            Adoor.Metadata.LogMessageEventHandler log = new Adoor.Metadata.LogMessageEventHandler(logMessageXmi);
            Adoor.Metadata.ProgressEventHandler prog1 = new Adoor.Metadata.ProgressEventHandler(progressXmi1);
            pivotFiles = makeTransformation((string)path, outXslt,
                "pivot.xml",
                log, prog1);
            analyseUUIDs();
        }

        private string[][] pivotFiles;

        private void analyseUUIDs()
        {
            if (pivotFiles != null)
            {
                foreach (string[] file in pivotFiles)
                {
                    string path = file[0];
                    string tableName = Path.GetFileNameWithoutExtension(path);

                    System.Text.StringBuilder sb = new System.Text.StringBuilder();

                    DataTable dt = dsProject.Tables["UUID"];
                    if (dt == null)
                    {
                        dt = new DataTable("UUID");
                        dt.Columns.Add("ClassName", typeof(string));
                        dt.Columns.Add("Id", typeof(int));
                        dt.Columns.Add("Pivot", typeof(string));
                        dsProject.Tables.Add(dt);
                    }


                    XmlDocument doc = new XmlDocument();
                    doc.Load(path);

                    int maxId = 1;
                    object val = dt.Compute("Max(Id)", "");
                    if (!DBNull.Value.Equals(val))
                        maxId = (int)val;

                    XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
                    nsmgr.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform");
                    nsmgr.AddNamespace("io", "urn:xmd-io");
                    nsmgr.AddNamespace("typing", "urn:xmd-typing");
                    foreach (XmlElement node in doc.SelectNodes("//*[typing:entity]", nsmgr))
                    {
                        if (dt.Select(string.Concat("ClassName = '", node.Name, "' and Pivot = '", tableName, "'")).Length == 0)
                        {
                            dt.Rows.Add(new object[] { 
                                node.Name, 
                                maxId++, 
                                tableName
                                });
                        }
                    }
                }
            }
        }

        private void logMessageXmi(object sender, Adoor.Metadata.LogMessageEventArgs e)
        {
            Invoke(new ThreadStart(delegate()
            {
                labelProgressPivot.Text = e.Message;
            }));
        }

        private void logMessageMapping(object sender, Adoor.Metadata.LogMessageEventArgs e)
        {
            Invoke(new ThreadStart(delegate()
            {
                labelProgressMapping.Text = e.Message;
            }));
        }

        private void logMessageCode(object sender, Adoor.Metadata.LogMessageEventArgs e)
        {
            Invoke(new ThreadStart(delegate()
            {
                labelProgressCode.Text = e.Message;
            }));
        }

        private void logMessageDb(object sender, Adoor.Metadata.LogMessageEventArgs e)
        {
            Invoke(new ThreadStart(delegate()
            {
                labelProgressDb.Text = e.Message;
            }));
        }

        private void progressXmi1(object sender, Adoor.Metadata.ProgressEventArgs e)
        {
            Invoke(new ThreadStart(delegate()
            {
                progressBarPivot.Maximum = Math.Max(e.Total - 1, e.Current);
                progressBarPivot.Value = e.Current;
            }));
        }

        private void progressMapping1(object sender, Adoor.Metadata.ProgressEventArgs e)
        {
            Invoke(new ThreadStart(delegate()
            {
                progressBarMapping2.Maximum = Math.Max(e.Total - 1, e.Current);
                progressBarMapping2.Value = e.Current;
            }));
        }

        private void progressCode1(object sender, Adoor.Metadata.ProgressEventArgs e)
        {
            Invoke(new ThreadStart(delegate()
            {
                progressBarCode2.Maximum = Math.Max(e.Total - 1, e.Current);
                progressBarCode2.Value = e.Current;
            }));
        }

        private void progressDb1(object sender, Adoor.Metadata.ProgressEventArgs e)
        {
            Invoke(new ThreadStart(delegate()
            {
                progressBarDb2.Maximum = Math.Max(e.Total - 1, e.Current);
                progressBarDb2.Value = e.Current;
            }));
        }

        private string generateXsltXmiFile(string xmiPath)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(xmiPath);

            XmlNode xmiNode = doc.SelectSingleNode("/XMI");

            string uml = xmiNode.GetNamespaceOfPrefix("UML");
            string uml2 = xmiNode.GetNamespaceOfPrefix("UML2");

            System.IO.StreamReader sr = new System.IO.StreamReader(xmiXslt, System.Text.Encoding.Default, true);
            string fullDoc = sr.ReadToEnd();
            sr.Close();

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            string[] strs = System.Text.RegularExpressions.Regex.Split(fullDoc, "(?:<UMLDataType>)");
            sb.Append(strs[0]);
            if (strs.Length > 0)
            {

                DataTable dt = TableUMLDataTypes;

                string defaultVal = string.Empty;

                foreach (DataRow dr in dt.Rows)
                {
                    string cond = dr[0].ToString();
                    if (string.Compare(cond, " default", true) != 0)
                        sb.AppendFormat("<xsl:template match=\"UML:DataType[{0}]\">{1}</xsl:template>\n", cond, dr[1]);
                    else
                        defaultVal = string.Format("<xsl:template match=\"UML:DataType[@name]\">{0}</xsl:template>\n", dr[1]);
                }

                sb.Append(defaultVal);

                strs = System.Text.RegularExpressions.Regex.Split(fullDoc, "(?:</UMLDataType>)");
                sb.Append(strs[1]);
            }
            string result = System.IO.Path.Combine(outputPath, "XMI.xslt");
            System.IO.StreamWriter sw = System.IO.File.CreateText(result);

            fullDoc = sb.ToString();
            fullDoc = System.Text.RegularExpressions.Regex.Replace(fullDoc,
                @"xmlns\:UML=""[^""]*""", "xmlns:UML=\"" + uml + "\"");
            fullDoc = System.Text.RegularExpressions.Regex.Replace(fullDoc,
                            @"xmlns\:UML2=""[^""]*""", "xmlns:UML2=\"" + uml2 + "\"");


            sw.Write(fullDoc);
            sw.Close();
            return result;
        }


        private void buttonUUIDs_Click(object sender, EventArgs e)
        {

        }

        private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void openProject()
        {
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                ofd.Title = "Open project";
                ofd.DefaultExt = ".adoorwzd";
                ofd.Filter = "Adoor project wizard (*.adoorwzd)|*.adoorwzd";
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    System.Runtime.Serialization.Formatters.Soap.SoapFormatter sf = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
                    Hashtable htProject;
                    using (FileStream fs = System.IO.File.OpenRead(ofd.FileName))
                    {
                        htProject = sf.Deserialize(fs) as Hashtable;
                        fs.Close();
                    }

                    dsProject = htProject[ProjectDataSet] as DataSet;
                    textBoxXmiFilePath.Text = (string)htProject[ProjectInput];
                    textBoxOutput.Text = (string)htProject[ProjectDest];

                    if (htProject.Contains(ProjectGenerateCode))
                        checkBoxCode.Checked = (bool)htProject[ProjectGenerateCode];
                    if (htProject.Contains(ProjectGenerateDb))
                        checkBoxDBScripts.Checked = (bool)htProject[ProjectGenerateDb];
                    if (htProject.Contains(ProjectGenerateMapping))
                        checkBoxMapping.Checked = (bool)htProject[ProjectGenerateMapping];

                    readComboConfig(htProject, ProjectCodeFile, comboBoxCode);
                    readComboConfig(htProject, ProjectDbFile, comboBoxDb);
                    readComboConfig(htProject, ProjectMappingFile, comboBoxMapping);
                    readComboConfig(htProject, ProjectPivotFile, comboBoxXmi);
                }
            }
        }

        private static void readComboConfig(Hashtable htProject, string key, ComboBox combo)
        {
            if (htProject.Contains(key))
            {
                int idx = combo.FindString(htProject[key].ToString());
                if (idx >= 0)
                    combo.SelectedIndex = idx;
            }
        }

        private void saveProject()
        {
            using (SaveFileDialog sd = new SaveFileDialog())
            {
                sd.Title = "Save project";
                sd.DefaultExt = ".adoorwzd";
                sd.Filter = "Adoor project wizard (*.adoorwzd)|*.adoorwzd";
                if (sd.ShowDialog() == DialogResult.OK)
                {
                    Hashtable htSave = new Hashtable();
                    htSave[ProjectDataSet] = dsProject;
                    htSave[ProjectInput] = textBoxXmiFilePath.Text;
                    htSave[ProjectDest] = textBoxOutput.Text;
                    htSave[ProjectGenerateCode] = checkBoxCode.Checked;
                    htSave[ProjectGenerateDb] = checkBoxDBScripts.Checked;
                    htSave[ProjectGenerateMapping] = checkBoxMapping.Checked;
                    htSave[ProjectCodeFile] = comboBoxCode.Text;
                    htSave[ProjectDbFile] = comboBoxDb.Text;
                    htSave[ProjectMappingFile] = comboBoxMapping.Text;
                    htSave[ProjectPivotFile] = comboBoxXmi.Text;

                    System.Runtime.Serialization.Formatters.Soap.SoapFormatter sf = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
                    using (FileStream fs = System.IO.File.OpenWrite(sd.FileName))
                    {
                        sf.Serialize(fs, htSave);
                        fs.Close();
                    }
                }
            }
        }


        private string[][] makeTransformation(string xmlFile, string xslFile
            , string defaultFileName
            , Adoor.Metadata.LogMessageEventHandler logMessageDlg
            , Adoor.Metadata.ProgressEventHandler progressDlg)
        {
            try
            {
                List<string[]> files = new List<string[]>();

                XslCompiledTransform xslTransform = new XslCompiledTransform(true);
                xslTransform.Load(xslFile);

                StringBuilder sb = new StringBuilder();

                XsltArgumentList args = new XsltArgumentList();
                XmlDocument xslDocument = new XmlDocument();
                xslDocument.Load(xslFile);
                foreach (XmlNode pi in xslDocument.SelectNodes("descendant::processing-instruction()[local-name()='arg']"))
                {
                    int pos = pi.Value.IndexOf("=");
                    if (pos == -1)
                        throw new Exception("processing instruction format error: expecting \"<?arg namespace=type ?>\"");
                    string ns = pi.Value.Substring(0, pos).Trim();
                    string typeName = pi.Value.Substring(pos + 1).Trim();
                    Type type = Type.GetType(typeName);
                    if (type == null)
                        throw new Exception("type " + typeName + " not found");
                    object arg = type.GetConstructor(new Type[] { }).Invoke(null);
                    args.AddExtensionObject(ns, arg);

                    Adoor.Metadata.IMessageProvider messageProvider = arg as Adoor.Metadata.IMessageProvider;
                    if (messageProvider != null)
                        messageProvider.LogMessage += logMessageDlg;

                    Adoor.Metadata.IProgress progressProvider = arg as Adoor.Metadata.IProgress;
                    if (progressProvider != null)
                        progressProvider.Progress += progressDlg;
                }

                XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
                nsmgr.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform");
                nsmgr.AddNamespace("io", "urn:xmd-io");

                if (xslDocument.SelectSingleNode("/xsl:stylesheet/xsl:output[@method='text']", nsmgr) != null)
                {
                    xslTransform.Transform(xmlFile, args, new StringWriter(sb));
                    string result = sb.ToString();
                    //while (result != "")
                    {
                        System.Text.RegularExpressions.Regex regex = new Regex(
                            @"\-\-\-\-\s*File\:\s*(?<file>[\\_\-\.\w]+)");
                        MatchCollection matches = regex.Matches(result);
                        int start = 0;
                        string defaultfile = "Result";
                        int cnt = 0;
                        string previousfile = "Result";
                        foreach (Match match in matches)
                        {
                            string file = match.Groups["file"].Value.Trim();
                            int newStart = match.Index + match.Length;
                            string data = sb.ToString(start, match.Index - start).Trim();
                            if (data != string.Empty)
                            {
                                if (previousfile == defaultfile)
                                    previousfile = defaultfile + (++cnt).ToString();

                                files.Add(new string[] { previousfile, data });
                            }
                            start = newStart;
                            previousfile = file;
                        }


                        string data2 = sb.ToString(start, sb.Length - start).Trim();
                        if (data2 != string.Empty)
                        {
                            if (previousfile == defaultfile)
                                previousfile = defaultfile + (++cnt).ToString();
                            files.Add(new string[] { previousfile, data2 });
                        }

                    }
                }
                else
                {

                    MultiFileDiskWriterProvider writerProvider = new MultiFileDiskWriterProvider(outputPath, defaultFileName);

                    using (XmlWriter xmlWriter = new Adoor.Metadata.XmlMultiFileWriter(writerProvider))
                    {
                        xslTransform.Transform(xmlFile, args, xmlWriter);
                        foreach (string file in writerProvider.Files)
                        {
                            files.Add(new string[] { file, string.Empty });
                        }
                    }
                }
                return files.ToArray();
            }
            finally
            {

            }
        }


        private string generateCodeMappingFile(string tableName)
        {
            System.IO.StreamReader sr = new System.IO.StreamReader(xsltCode, System.Text.Encoding.Default, true);
            string fullDoc = sr.ReadToEnd();
            sr.Close();

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            string[] strs = System.Text.RegularExpressions.Regex.Split(fullDoc, "<CSharpInput/>|<CSharpInput\\s*/>");
            sb.Append(strs[0]);

            if (strs.Length > 0)
            {
                DataTable dt = TableCodeDefault;

                string defaultVal = string.Empty;

                foreach (DataRow dr in dt.Rows)
                {
                    string cond = dr[0].ToString();
                    if (string.Compare(cond, " default", true) != 0)
                        sb.AppendFormat("<xsl:template match=\"@type[.='{0}']\">{1}</xsl:template>\n", cond, dr[1]);
                    else
                        defaultVal = string.Format("<xsl:template match='@type'>{0}</xsl:template>\n", dr[1]);
                }

                if (defaultVal == string.Empty)
                {
                    sb.Append("<xsl:template match='@type'><xsl:message terminate='yes'>datatype <xsl:value-of select='.'/> not defined</xsl:message></xsl:template>\n");
                }
                else
                {
                    sb.Append(defaultVal);
                }

                sb.Append(strs[1]);
            }
            string result = System.IO.Path.Combine(outputPath, "code." + tableName + ".xslt");
            System.IO.StreamWriter sw = System.IO.File.CreateText(result);
            sw.Write(sb.ToString());
            sw.Close();
            return result;
        }

        private string generateDataBaseMappingFile(string tableName)
        {
            System.IO.StreamReader sr = new System.IO.StreamReader(xsltDb, System.Text.Encoding.Default, true);
            string fullDoc = sr.ReadToEnd();
            sr.Close();

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            string[] strs = System.Text.RegularExpressions.Regex.Split(fullDoc, "<DBInput/>|<DBInput\\s/>");
            sb.Append(strs[0]);

            if (strs.Length > 0)
            {
                DataTable dt = TableDbDefault;

                string defaultVal = string.Empty;

                foreach (DataRow dr in dt.Rows)
                {
                    string cond = dr[0].ToString();
                    if (string.Compare(cond, " default", true) != 0)
                        sb.AppendFormat("<xsl:template match=\"@type[.='{0}']\"><xsl:param name=\"classId\"/>{1}</xsl:template>\n", cond, dr[1]);
                    else
                        defaultVal = string.Format("<xsl:template match='@type'><xsl:param name=\"classId\"/>{0}</xsl:template>\n", dr[1]);
                }

                if (defaultVal == string.Empty)
                {
                    sb.Append("<xsl:template match='@type'><xsl:message terminate='yes'>datatype <xsl:value-of select='.'/> not defined</xsl:message></xsl:template>\n");
                }
                else
                {
                    sb.Append(defaultVal);
                }

                sb.Append(strs[1]);

                fullDoc = sb.ToString();

                sb = new System.Text.StringBuilder();
                strs = System.Text.RegularExpressions.Regex.Split(fullDoc, "<UUIDInput/>|<UUIDInput\\s/>");
                sb.Append(strs[0]);

                if (strs.Length > 0)
                {
                    dt = TableClassIds;
                    DataRow[] drs = dt.Select("Pivot = '" + tableName + "'", "");

                    foreach (DataRow dr in drs)
                    {
                        sb.AppendFormat("<xsl:when test=\"$className = '{0}'\">{1}</xsl:when>\n", dr[0], dr[1]);
                    }

                    sb.Append(strs[1]);
                }
            }

            string result = System.IO.Path.Combine(outputPath, "DBInput." + tableName + ".xslt");
            System.IO.StreamWriter sw = System.IO.File.CreateText(result);
            sw.Write(sb.ToString());
            sw.Close();
            return result;
        }

        private string generateXsltMappingFile(string tableName)
        {
            System.IO.StreamReader sr = new System.IO.StreamReader(xsltMapping, System.Text.Encoding.Default, true);
            string fullDoc = sr.ReadToEnd();
            sr.Close();

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            string[] strs = System.Text.RegularExpressions.Regex.Split(fullDoc, "<MapInput/>|<MapInput\\s/>");
            sb.Append(strs[0]);

            DataTable dt = TableClassIds;

            foreach (DataRow dr in dt.Rows)
            {
                sb.AppendFormat("<xsl:when test=\"local-name($classNode) = '{0}'\">{1}</xsl:when>\n", dr[0], dr[1]);
            }

            sb.Append(strs[1]);
            string result = System.IO.Path.Combine(outputPath, "Mapping." + tableName + ".xslt");
            System.IO.StreamWriter sw = System.IO.File.CreateText(result);
            sw.Write(sb.ToString());
            sw.Close();
            return result;
        }


        private void transforms(object state)
        {
            if (generateMapping)
            {
                ThreadStart ts = new ThreadStart(transformsMapping);
                ts.BeginInvoke(new AsyncCallback(endTransformsMapping), ts);
            }
            if (generateCode)
            {
                ThreadStart ts = new ThreadStart(transformsCode);
                ts.BeginInvoke(new AsyncCallback(endTransformsCode), ts);                
            }
            if (generateDb)
            {
                ThreadStart ts = new ThreadStart(transformsDb);
                ts.BeginInvoke(new AsyncCallback(endTransformsDb), ts);
            }
        }

        private void endTransformsMapping(IAsyncResult res)
        {
            try
            {
                ThreadStart ts = (ThreadStart)res.AsyncState;
                ts.EndInvoke(res);
            }
            catch (Exception ex)
            {
                Invoke(new ThreadStart(delegate()
                {
                    MessageBox.Show(ex.ToString());
                }));                
            }
        }

        private void endTransformsCode(IAsyncResult res)
        {
            try
            {
                ThreadStart ts = (ThreadStart)res.AsyncState;
                ts.EndInvoke(res);
            }
            catch (Exception ex)
            {
                Invoke(new ThreadStart(delegate()
                {
                    MessageBox.Show(ex.ToString());
                }));
            }
        }

        private void endTransformsDb(IAsyncResult res)
        {
            try
            {
                ThreadStart ts = (ThreadStart)res.AsyncState;
                ts.EndInvoke(res);
            }
            catch (Exception ex)
            {
                Invoke(new ThreadStart(delegate()
                {
                    MessageBox.Show(ex.ToString());
                }));
            }
        }


        private void transformsDb()
        {
            int cnt = 0;
            Invoke(new ThreadStart(delegate()
            {
                progressBarDb.Maximum = pivotFiles.Length;
            }));
            foreach (string[] file in pivotFiles)
            {
                cnt++;
                string name = Path.GetFileNameWithoutExtension(file[0]);
                string outXslt = generateDataBaseMappingFile(name);
                Adoor.Metadata.LogMessageEventHandler log = new Adoor.Metadata.LogMessageEventHandler(logMessageDb);
                Adoor.Metadata.ProgressEventHandler prog1 = new Adoor.Metadata.ProgressEventHandler(progressDb1);
                string[][] scripts = makeTransformation(
                    file[0], outXslt,
                    "Result",
                    log, prog1);
                foreach (string[] fileResult in scripts)
                {
                    if (fileResult[1].Length > 0)
                    {
                        string path = Path.Combine(outputPath, "scripts");
                        Directory.CreateDirectory(path);
                        path = Path.Combine(path, fileResult[0]);
                        File.WriteAllText(path, fileResult[1]);
                    }
                }

                Invoke(new ThreadStart(delegate()
                {
                    progressBarDb.Value = cnt;
                }));
            }
        }

        private void transformsCode()
        {
            int cnt = 0;
            Invoke(new ThreadStart(delegate()
            {
                progressBarCode.Maximum = pivotFiles.Length;
            }));
            foreach (string[] file in pivotFiles)
            {
                cnt++;
                string name = Path.GetFileNameWithoutExtension(file[0]);
                string outXslt = generateCodeMappingFile(name);
                Adoor.Metadata.LogMessageEventHandler log = new Adoor.Metadata.LogMessageEventHandler(logMessageCode);
                Adoor.Metadata.ProgressEventHandler prog1 = new Adoor.Metadata.ProgressEventHandler(progressCode1);
                string[][] codeFiles = makeTransformation(
                    file[0], outXslt,
                    "Result",
                    log, prog1);

                int cnt2 = 0;

                Invoke(new ThreadStart(delegate()
                {
                    progressBarCodeMerging.Maximum = codeFiles.Length;
                }));
                foreach (string[] fileResult in codeFiles)
                {
                    cnt2++;
                    string path = Path.Combine(outputPath, fileResult[0]);
                    string folder = Path.GetDirectoryName(path);
                    Directory.CreateDirectory(folder);

                    if (fileResult[1].Length > 0)
                    {
                        if (System.IO.File.Exists(path))
                            MergeData(fileResult[1], path);
                        else
                        {
                            File.WriteAllText(path, fileResult[1]);
                        }

                    }

                    Invoke(new ThreadStart(delegate()
                    {
                        progressBarCodeMerging.Value = cnt2;
                    }));
                }

                Invoke(new ThreadStart(delegate()
                {
                    progressBarCode.Value = cnt;
                }));
            }
        }

        private void transformsMapping()
        {
            int cnt = 0;
            Invoke(new ThreadStart(delegate()
            {
                progressBarMapping.Maximum = pivotFiles.Length;
            }));
            foreach (string[] file in pivotFiles)
            {
                cnt++;
                string name = Path.GetFileNameWithoutExtension(file[0]);
                string outXslt = generateXsltMappingFile(name);
                Adoor.Metadata.LogMessageEventHandler log = new Adoor.Metadata.LogMessageEventHandler(logMessageMapping);
                Adoor.Metadata.ProgressEventHandler prog1 = new Adoor.Metadata.ProgressEventHandler(progressMapping1);
                string[][] mappingFiles = makeTransformation(
                    file[0], outXslt,
                    "Mapping." + name + ".xml",
                    log, prog1);

                Invoke(new ThreadStart(delegate()
                {
                    progressBarMapping.Value = cnt;
                }));
            }
        }

        public void MergeData(string text, string fileName)
        {
            FileStream fs = File.OpenRead(fileName);
            StreamReader sr = new StreamReader(fs, System.Text.Encoding.Default, true);
            string existingFile = sr.ReadToEnd();
            string newFile = text;

            Regex regexExisting = new Regex(
                @"(?<region>\#region\s(?<def>user\scode\s[^\n]*))",
                RegexOptions.IgnoreCase | RegexOptions.Multiline
                | RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture
                | RegexOptions.Compiled);

            MatchCollection matchFcts = regexExisting.Matches(existingFile);
            foreach (Match match in matchFcts)
            {
                string def = match.Groups["def"].Value;
                string endRegion = string.Concat("#endregion ", def).Trim();
                def = Regex.Escape(def.Trim());
                int endExisting = existingFile.IndexOf(endRegion, match.Index);
                if (endExisting >= 0)
                {
                    Regex regexNewFile = new Regex(
                        string.Concat(@"(?<region>\#region\s", def, ")",
                        @"(?<code>[^#]*)(?<endregion-region>\#endregion\s", def, @"(?<endspace>\s))"),
                        RegexOptions.IgnoreCase | RegexOptions.Multiline
                        | RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture
                        | RegexOptions.Compiled);
                    newFile = regexNewFile.Replace(newFile, string.Concat(existingFile.Substring(match.Index, endExisting + endRegion.Length - match.Index), "${endspace}"));
                }
            }
            sr.Close();
            fs.Close();
            File.WriteAllText(fileName, newFile);
        }


    }

}